package ${packageName}.service.mapper;

import com.boss.core.annotation.mapstruct.DateStringToInstantMapper;
import com.boss.core.base.service.mapper.BaseMapper;
import com.boss.core.util.DateTimeUtil;
import com.boss.core.base.service.mapper.BaseMapper;
import ${packageName}.domain.${classInfo.className};
import ${packageName}.dto.${classInfo.className}DTO;

import java.time.Instant;
import java.util.Objects;
import org.apache.commons.lang3.StringUtils;
import org.mapstruct.BeanMapping;
import org.mapstruct.BeforeMapping;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.MappingTarget;
import org.mapstruct.NullValueCheckStrategy;
import org.mapstruct.NullValuePropertyMappingStrategy;
import org.mapstruct.factory.Mappers;

/**
 * ${classInfo.classComment}
 *
 * @author ${authorName} ${.now?string('yyyy-MM-dd')}
 */

@Mapper
public interface ${classInfo.className}Mapper extends BaseMapper<${classInfo.className}, ${classInfo.className}DTO> {

    ${classInfo.className}Mapper INSTANCE = Mappers.getMapper(${classInfo.className}Mapper.class);


    /**
     * convert ${classInfo.className}  to ${classInfo.className}DTO
     *
     * @param ${classInfo.className?uncap_first}
     * @return
     */
    @Override
    ${classInfo.className}DTO toDTO(${classInfo.className} ${classInfo.className?uncap_first});


    /**
     * convert ${classInfo.className}DTO to ${classInfo.className}
     *
     * @param dto
     * @return
     */
    @Override
    <@buildInstantMapping qualifiedBy="DateStringToInstantMapper.class"/>
    ${classInfo.className} toEntity(${classInfo.className}DTO dto);


    /**
     * Set Entity field value with DTO field which value is not null
     *
     * @param dto
     * @param ${classInfo.className?uncap_first}
     * @return
     */
    @Override
    @BeanMapping(nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE,
        nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS)
    <@buildInstantMapping qualifiedBy="DateStringToInstantMapper.class"/>
    ${classInfo.className} toEntity(${classInfo.className}DTO dto, @MappingTarget ${classInfo.className} ${classInfo.className?uncap_first});

    @DateStringToInstantMapper
    static Instant dateStringToInstant(String date) {
        if (StringUtils.isBlank(date)) {
            return null;
        }
        return DateTimeUtil.getInstant(date);
    }

    @BeforeMapping
    static void requireNonNull(Object anySource, @MappingTarget Object target) {
        Objects.requireNonNull(anySource, "[${classInfo.className}Mapper] Source bean must not be null");
        Objects.requireNonNull(target, "[${classInfo.className}Mapper] Target bean must not be null");
    }


    /**
     * convert ${classInfo.className}DTOList  to ${classInfo.className}List
     *
     * @param ${classInfo.className?uncap_first}DTOList
     * @return
     */
     default List<${classInfo.className}> toEntityList(List<${classInfo.className}DTO> ${classInfo.className?uncap_first}DTOList) {
        BeanUtil.checkNotNull(${classInfo.className?uncap_first}DTOList, "${classInfo.className?uncap_first}DTOList must not be null");
        return ${classInfo.className?uncap_first}DTOList.stream()
        .filter(Objects::nonNull)
        .map(this::toEntity)
        .collect(Collectors.toList());
     }
    /**
     * convert ${classInfo.className}List  to ${classInfo.className}DTOList
     *
     * @param ${classInfo.className?uncap_first}List
     * @return
     */
    default List<${classInfo.className}DTO> toDTOList(List<${classInfo.className}> ${classInfo.className?uncap_first}List) {
        BeanUtil.checkNotNull(${classInfo.className?uncap_first}List, "${classInfo.className?uncap_first}List must not be null");
        return ${classInfo.className?uncap_first}List.stream()
        .filter(Objects::nonNull)
        .map(this::toDTO)
        .collect(Collectors.toList());
    }


<#if !!useProtobuf>

    @ProtoTimestampToInstantMapper
    static Instant protoTimestampToInstant(google.protobuf.Timestamp timestamp) {
        if (StringUtils.isBlank(timestamp)) {
        return null;
        }
        return DateTimeUtil.toInstant(timestamp);
    }
    /**
     * convert protobuf to entity
     * @param proto
     * @return entity
     */
    <@buildInstantMapping qualifiedBy="ProtoTimestampToInstantMapper.class"/>
    ${classInfo.className} toEntity(${packageName}.proto.${classInfo.className} proto);

    </#if>
    /**
     * convert entity to protobuf
     * @param ${classInfo.className?uncap_first}
     * @return protobuf
     */
    default ${packageName}.proto.${classInfo.className} toProtobuf(${classInfo.className} ${classInfo.className?uncap_first}) {
        return ${packageName}.proto.${classInfo.className}.newBuilder()
    <#list classInfo.fieldList as fieldItem >
    <#if fieldItem.fieldClass == "Instant">
        .set${fieldItem.fieldName?cap_first}(DateTimeUtil.toTimestamp(${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}()))
    <#else>
        .set${fieldItem.fieldName?cap_first}(${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}())
    </#if>
    </#list>
        .build();

    }
}







<#macro buildInstantMapping qualifiedBy>
    <#list classInfo.fieldList as fieldItem >
        <#if  (fieldItem.fieldClass == "Instant")>
    @Mapping(source = "${fieldItem.fieldName}", target = "${fieldItem.fieldName}", qualifiedBy = ${qualifiedBy})
        </#if>
    </#list>
</#macro>